package tech.wangtong.util;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

//jdbc工具类封装:
//1.加载驱动类    1次
//2.创建连接     多次
//3.创建预编译对象 多次
//4.执行sql语句 多次
//5.处理结果集  多次
//6.关闭  多次
public class DBUtil {
    //四个变量 由于会经常改变 环境换了 对应driver url都要换
    //只要改变都去修改java代码是非常不可取的
    //所以要把经常改的属性提取出来  写入到配置文件(xml properties yml..)
    //以后想改环境 不需要改java代码 只需要修改配置文件
    private static String driver;
    private static String url;
    private static String username;
    private static String password;
    static{
        try {
            //先读取properties配置文件
            InputStream is=
                    DBUtil.class.getClassLoader()
                            //地址 从根目录开始 匹配文件的
                            .getResourceAsStream("jdbc.properties");
            Properties p=new Properties();
            p.load(is);//把读取的数据 给p对象封装起来
            //根据key获取value给属性赋值
            driver=p.getProperty("driver");
            url=p.getProperty("url");
            username=p.getProperty("username");
            password=p.getProperty("password");
            //加载驱动类
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //创建连接的通用方法
    public static Connection getConn(){
        Connection conn= null;
        try {
            conn = DriverManager
                    .getConnection(url,username,password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        System.out.println(conn);
        return conn;
    }
    //关闭资源的通用方法 rs.close  stmt.close  conn.close
    //类型 不确定(写三者父类AutoCloseable)
    //关闭的个数也不确定(可变长参数 ...)
    //bug: 传参的顺序 就是我关闭的顺序(先创建后关闭)
    public static void close(AutoCloseable ... o){
        for(AutoCloseable a:o){
            try {
               if(a!=null) a.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    //增删改 通用方法
    //返回值 int: 因为都是通过executeUpdate执行的
    //参数: sql语句每次都不一样, sql语句中?参数也不一样
    //bug: 参数传递的顺序和个数 必须和sql语句的? 是一一对应的
    public static int update(String sql,Object ... o){
        Connection conn=getConn();
        PreparedStatement pstmt= null;
        int result= 0;
        try {
            pstmt = conn.prepareStatement(sql);
            if(o!=null){//表示有参数 需要给?赋值
                for(int i=0;i<o.length;i++){
                   //pstmt.set类型(?个数,参数的值);
                    pstmt.setObject(i+1,o[i]);
                }
            }
            result = pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(pstmt,conn);
        }
        return result;
    }
    //查询  通用方法 :相比增删改通用方法  返回值是不确定的
    //比如: 查询人数 应该返回int  实现登录功能: 返回的登录对象
    //实现查询班级学生信息: 返回学生对象集合
    public static Connection conn;
    public static PreparedStatement pstmt;
    public static ResultSet select(String sql,Object ... o){
        conn=getConn();
        ResultSet rs= null;
        try {
            pstmt=conn.prepareStatement(sql);
            if(o!=null){//表示有参数 需要给?赋值
                for(int i=0;i<o.length;i++){
                    //pstmt.set类型(?个数,参数的值);
                    pstmt.setObject(i+1,o[i]);
                }
            }
            rs = pstmt.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //这里不能关闭资源  否则外面就无法使用rs了
        //close(rs,pstmt,conn);
        return rs;
    }

//    public static void main(String[] args) {
//        ResultSet rs=select(???);
//        List<Emp> list=new ArrayList();
//        while(rs.next()){
//            ...
//        }
//        DBUtil.close(rs,DBUtil.pstmt,DBUtil.conn);
//    }
}
